package xyz.labmem.core.util.gui.loading

import io.github.palexdev.materialfx.controls.MFXProgressBar
import io.github.palexdev.materialfx.controls.MFXProgressSpinner
import io.github.palexdev.materialfx.dialogs.MFXGenericDialog
import io.github.palexdev.materialfx.dialogs.MFXGenericDialogBuilder
import io.github.palexdev.materialfx.dialogs.MFXStageDialog
import io.github.palexdev.materialfx.enums.ScrimPriority
import javafx.application.Platform
import javafx.beans.property.DoubleProperty
import javafx.beans.property.SimpleStringProperty
import javafx.concurrent.Task
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.scene.Node
import javafx.scene.control.Label
import javafx.scene.layout.VBox
import javafx.scene.text.Font
import javafx.stage.Modality
import javafx.stage.Window
import kotlinx.coroutines.*
import xyz.labmem.core.util.gui.loading.LoadingType.*


/**
 * @description: do something
 * @author: liutianyu
 * @date: 2022/11/9 13:56
 */
class LoadingAlert(private val window: Window?) {

    private var dialogContent: MFXGenericDialog = MFXGenericDialogBuilder()
        .setShowClose(false)
        .setShowMinimize(false)
        .setShowAlwaysOnTop(false)
        .get()

    private var dialog: MFXStageDialog = MFXGenericDialogBuilder.build(dialogContent)
        .toStageDialogBuilder().apply {
            initOwner(window)
            initModality(Modality.APPLICATION_MODAL)
            //可拖动
            setDraggable(false)
            setTitle("加载模态")
            setScrimPriority(ScrimPriority.WINDOW)
            setScrimOwner(true)
        }.get()

    private var type: LoadingType = SPINNERS

    private var progressPy: DoubleProperty? = null

    private var msg: SimpleStringProperty = SimpleStringProperty("loading..")

    fun loadingType(type: LoadingType): LoadingAlert {
        this.type = type
        return this
    }

    fun setHeaderText(title: String): LoadingAlert {
        dialogContent.headerText = title
        return this
    }

    fun setHeaderIcon(headerIcon: Node): LoadingAlert {
        dialogContent.headerIcon = headerIcon
        return this
    }

    fun setMsg(msg: String): LoadingAlert {
        this.msg.set(msg)
        return this
    }

    fun show(): LoadingAlert {
        draw()
        dialog.show()
        return this
    }

    fun close() {
        dialog.close()
    }

    @OptIn(DelicateCoroutinesApi::class)
    fun make(task: (() -> Unit)) {
        show()
        GlobalScope.launch(Dispatchers.Main) {
            withContext(Dispatchers.IO) {
                task()
            }
            dialog.close()
        }
    }

    @OptIn(DelicateCoroutinesApi::class)
    fun make(task: Task<*>, needFx: Boolean = false, back: (() -> Unit)? = null) {
        draw()
        taskInit(task, back)
        if (needFx)
            Thread { Platform.runLater(task) }.start()
        else
            Thread(task).start()
    }

    @DelicateCoroutinesApi
    private fun taskInit(task: Task<*>, back: (() -> Unit)? = null) {
        dialog.show()
        msg.bind(task.messageProperty())
        progressPy?.bind(task.progressProperty())
        task.setOnSucceeded {
            msg.unbind()
            progressPy?.unbind()
            dialog.close()
            back?.let { it() }
        }
        task.setOnFailed {
            msg.unbind()
            progressPy?.unbind()
            dialog.close()
            back?.let { it() }
        }
        task.setOnCancelled {
            msg.unbind()
            progressPy?.unbind()
            dialog.close()
            back?.let { it() }
        }
    }

    private fun draw() {
        when (type) {
            SPINNERS -> {
                dialogContent.content = VBox().apply {
                    minWidth = 150.0
                    alignment = Pos.CENTER
                    dialogContent.setMinSize(this.prefWidth, this.prefHeight)
                    children.add(MFXProgressSpinner().apply {
                        setPrefSize(60.0, 60.0)
                        progressPy = progressProperty()
                    })
                    children.add(Label().apply {
                        textProperty().bind(msg)
                        VBox.setMargin(this, Insets(15.0, 0.0, 15.0, 0.0))
                        font = Font.font(18.0)
                    })
                }
            }

            BARS -> {
                dialogContent.content = VBox().apply vbox@{
                    minWidth = 450.0
                    alignment = Pos.CENTER
                    dialogContent.setMinSize(this.prefWidth, this.prefHeight)
                    children.add(MFXProgressBar().apply {
                        prefHeight = 5.0
                        prefWidthProperty().bind(this@vbox.widthProperty().subtract(20))
                        progressPy = progressProperty()
                    })
                    children.add(Label().apply {
                        textProperty().bind(msg)
                        VBox.setMargin(this, Insets(15.0, 0.0, 15.0, 0.0))
                        font = Font.font(18.0)
                    })
                }
            }
        }
    }

}